<?php

namespace addons\yungift\library;

class Super
{
    /**
     * @param array|object $origin
     * @param array $keys
     * @param null $default
     * @param bool $list
     * @return array
     */
    public static function arrayGetSet(
        $origin,
        array $keys = ['a' => 'b', 'a', 'c'],
        $list = false,
        $default = null
    ) {
        $result = [];
        if ($list && empty($origin)) {
            return $result;
        }
        if ($list) {
            foreach ($origin as $key => $item) {
                if (is_array($item) || is_object($item)) {
                    $result[$key] = self::arrayGetSet($item, $keys, false, $default);
                }
            }
        } else {
            foreach ($keys as $key => $value) {
                if (! is_string($key)) {
                    $key = $value;
                }
                if (! is_string($key) && is_callable($value)) {  // 支持回调赋值
                    $data = $value($origin);
                } else {
                    $data = Super::getValue($origin, $value, $default);
                }
                Super::setValue($result, $key, $data);
            }
        }

        return $result;
    }

    /**
     * @param $array
     * @param $key
     * @param array $groups
     * @return array|mixed
     */
    public static function arrayIndex($array, $key, $groups = [])
    {
        $result = [];
        $groups = (array)$groups;

        foreach ($array as $element) {
            $lastArray = &$result;

            foreach ($groups as $group) {
                $value = static::getValue($element, $group);
                if (! array_key_exists($value, $lastArray)) {
                    $lastArray[$value] = [];
                }
                $lastArray = &$lastArray[$value];
            }

            if ($key === null) {
                if (! empty($groups)) {
                    $lastArray[] = $element;
                }
            } else {
                $value = static::getValue($element, $key);
                if ($value !== null) {
                    if (is_float($value)) {
                        $value = str_replace(',', '.', (string)$value);
                    }
                    $lastArray[$value] = $element;
                }
            }
            unset($lastArray);
        }

        return $result;
    }

    /**
     * @param $array
     * @param $key
     * @param null $default
     * @return mixed|null
     */
    public static function getValue($array, $key, $default = null)
    {
        if ($key instanceof \Closure) {
            return $key($array, $default);
        }

        if (is_array($key)) {
            $lastKey = array_pop($key);
            foreach ($key as $keyPart) {
                $array = static::getValue($array, $keyPart);
            }
            $key = $lastKey;
        }

        if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) {
            return $array[$key];
        }

        if (($pos = strrpos($key, '.')) !== false) {
            $array = static::getValue($array, substr($key, 0, $pos), $default);
            $key = substr($key, $pos + 1);
        }

        if (is_object($array)) {
            return $array->$key;
        }
        if (is_array($array)) {
            return (isset($array[$key]) || array_key_exists($key, $array)) ? $array[$key] : $default;
        }

        return $default;
    }

    /**
     * @param $array
     * @param $path
     * @param $value
     */
    public static function setValue(&$array, $path, $value)
    {
        if ($path === null) {
            $array = $value;

            return;
        }

        $keys = is_array($path) ? $path : explode('.', $path);

        while (count($keys) > 1) {
            $key = array_shift($keys);
            if (! isset($array[$key])) {
                $array[$key] = [];
            }
            if (! is_array($array[$key])) {
                $array[$key] = [$array[$key]];
            }
            $array = &$array[$key];
        }

        $array[array_shift($keys)] = $value;
    }

    /**
     * @param array $values
     * @param int $count
     * @return array
     */
    public static function arrayRand(array $values, int $count)
    {
        if (! $values) {
            return [];
        }
        $valuesCount = count($values);
        if ($count > $valuesCount) {
            $count = $valuesCount;
        }
        $randKeys = array_rand($values, $count);
        if (! is_array($randKeys)) {
            $randKeys = [$randKeys];
        }
        $results = [];
        foreach ($randKeys as $key) {
            $results[] = $values[$key];
        }

        return $results;
    }

    /**
     * @param array $counter
     * @param string $key
     * @param int $count
     * @return mixed
     */
    public static function counter(array &$counter, $key = 'default', $count = 1)
    {
        if (array_key_exists($key, $counter)) {
            $counter[$key] += $count;
        } else {
            $counter[$key] = $count;
        }

        return $counter[$key];
    }

    /**
     * 发送阿里云云短信
     *
     * @param $mobile
     * @param array $TemplateParam
     * @param string $TemplateCode
     * @param string $accessKeyId
     * @param string $accessKeySecret
     * @param string $signName
     * @return bool
     */
    public static function sendAliyunPhoneCode(
        $mobile,
        $TemplateParam = [],
        $TemplateCode = '',
        $accessKeyId = '',
        $accessKeySecret = '',
        $signName = ''
    ) {
        $params = [];

        // 短信接收号码
        $params['PhoneNumbers'] = $mobile;

        // 短信签名
        $params['SignName'] = $signName;

        // 短信模板Code
        $params['TemplateCode'] = $TemplateCode;

        // 短信模板参数
        $params['TemplateParam'] = $TemplateParam ?: null;  // 没有参数时，默认null

        // 发送短信流水号，选填
        $params['OutId'] = "";

        // 上行短信扩展码, 扩展码字段控制在7位或以下，选填
        $params['SmsUpExtendCode'] = "";

        if (! empty($params['TemplateParam']) && is_array($params['TemplateParam'])) {
            $params['TemplateParam'] = json_encode($params['TemplateParam'], JSON_UNESCAPED_UNICODE);
        }

        // 此处可能会抛出异常，注意catch
        $content = self::sendAliyunServiceRequest(
            $accessKeyId,
            $accessKeySecret,
            "dysmsapi.aliyuncs.com",
            array_merge($params, [
                "RegionId" => "cn-hangzhou",
                "Action"   => "SendSms",
                "Version"  => "2017-05-25",
            ]), true
        );

        return $content;
    }

    /**
     * 发起阿里云请求
     *
     * @param $accessKeyId
     * @param $accessKeySecret
     * @param $domain
     * @param $params
     * @param false $security
     * @return false|mixed
     * @throws \Exception
     */
    public static function sendAliyunServiceRequest($accessKeyId, $accessKeySecret, $domain, $params, $security = false)
    {
        // 生成签名
        $apiParams = array_merge(array(
            "SignatureMethod"  => "HMAC-SHA1",
            "SignatureNonce"   => uniqid(random_int(0, 0xffff), true),
            "SignatureVersion" => "1.0",
            "AccessKeyId"      => $accessKeyId,
            "Timestamp"        => gmdate("Y-m-d\TH:i:s\Z"),
            "Format"           => "JSON",
        ), $params);
        ksort($apiParams);
        $sortedQueryStringTmp = "";
        foreach ($apiParams as $key => $value) {
            $sortedQueryStringTmp .= "&" . self::urlEncode($key) . "=" . self::urlEncode($value);
        }
        $stringToSign = "GET&%2F&" . self::urlEncode(substr($sortedQueryStringTmp, 1));
        $sign = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&", true));
        $signature = self::urlEncode($sign);

        // 发起请求
        $url = ($security ? 'https' : 'http') . "://{$domain}/?Signature={$signature}{$sortedQueryStringTmp}";
        try {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_TIMEOUT, 5);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                "x-sdk-client" => "php/2.0.0"
            ));
            if (substr($url, 0, 5) === 'https') {
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            }
            $content = curl_exec($ch);
            if ($content === false) {
                trigger_error("[CURL_" . curl_errno($ch) . "]: " . curl_error($ch), E_USER_ERROR);
            }
            curl_close($ch);

            return json_decode($content, true);
        } catch (\Exception $e) {
            return false;
        }
    }

    public static function urlEncode($str)
    {
        $res = urlencode($str);
        $res = str_replace(["+", "*"], ["%20", "%2A"], $res);
        $res = preg_replace("/%7E/", "~", $res);

        return $res;
    }

    /**
     * 发起阿里云市场API调用
     *
     * @param $appcode
     * @param $api
     * @param $method
     * @param $data
     * @return false|mixed|string
     */
    public static function requestAliCloudApi($appcode, $api, $method, $data)
    {
        $headers = ['Authorization:APPCODE ' . $appcode];
        if ($method === 'GET') {
            $url = $api . '?' . http_build_query($data);
        }

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, true);

        if (1 == strpos('$' . $api, 'https://')) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        }
        $out_put = curl_exec($curl);

        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        list($header, $body) = explode("\r\n\r\n", $out_put, 2);
        if ($httpCode == 200) {
            return $body;
        }
        if ($httpCode == 400 && strpos($header, 'Invalid Param Location') !== false) {
            print('参数错误');
        } elseif ($httpCode == 400 && strpos($header, 'Invalid AppCode') !== false) {
            print('AppCode错误');
        } elseif ($httpCode == 400 && strpos($header, 'Invalid Url') !== false) {
            print('请求的 Method、Path 或者环境错误');
        } elseif ($httpCode == 403 && strpos($header, 'Unauthorized') !== false) {
            print('服务未被授权（或URL和Path不正确）');
        } elseif ($httpCode == 403 && strpos($header, 'Quota Exhausted') !== false) {
            print('套餐包次数用完');
        } elseif ($httpCode == 403 && strpos($header, 'Api Market Subscription quota exhausted') !== false) {
            print('套餐包次数用完，请续购套餐');
        } elseif ($httpCode == 500) {
            print('API网关错误');
        } elseif ($httpCode == 0) {
            print('URL错误');
        } else {
            print('参数名错误 或 其他错误');
            print($httpCode);
            $headers = explode("\r\n", $header);
            $headList = array();
            foreach ($headers as $head) {
                $value = explode(':', $head);
                $headList[$value[0]] = $value[1];
            }
            print($headList['x-ca-error-message']);
        }

        return false;
    }

    /**
     * 字符串隐藏
     *
     * @param $str
     * @return string
     */
    public static function stringHide($str, $prefixCount = 2, $suffixCount = 2, $hideCount = 3)
    {
        if (empty($str)) {
            return $str;
        }

        // 判断是否包含中文字符
        if (preg_match("/[\x{4e00}-\x{9fa5}]+/u", $str)) {
            // 按照中文字符计算长度
            $len = mb_strlen($str, 'UTF-8');
            if ($len >= 3) {
                // 三个字符或三个字符以上掐头取尾，中间用*代替
                if ($leftCount = $len - $prefixCount - $suffixCount) {
                    if ($leftCount < $hideCount) {
                        $hideCount = $leftCount;
                    }
                }
                $str = mb_substr($str, 0, $prefixCount, 'UTF-8')
                    . str_pad('', $hideCount, '*')
                    . mb_substr($str, -$suffixCount, $suffixCount, 'UTF-8');
            } elseif ($len == 2) {
                // 两个字符
                $str = mb_substr($str, 0, 1, 'UTF-8') . '*';
            }
        } else {
            // 按照英文字串计算长度
            $len = strlen($str);
            if ($len >= 3) {
                // 三个字符或三个字符以上掐头取尾，中间用*代替
                if ($leftCount = $len - $prefixCount - $suffixCount) {
                    if ($leftCount < $hideCount) {
                        $hideCount = $leftCount;
                    }
                }
                $str = substr($str, 0, $prefixCount) . str_pad('', $hideCount, '*') . substr($str, -$suffixCount);
            } elseif ($len == 2) {
                // 两个字符
                $str = substr($str, 0, 1) . '*';
            }
        }

        return $str;
    }

    /**
     * 截取中文字符串
     *
     * @param string $str
     * @param int $length
     * @param string $suffix
     * @param int $start
     * @param string $charset
     * @return string
     */
    public static function substrText(string $str, int $length, $suffix = '', $start = 0, $charset = 'utf-8')
    {
        if (function_exists('mb_substr')) {
            $content = mb_substr($str, $start, $length, $charset);
        } elseif (function_exists('iconv_substr')) {
            $content = iconv_substr($str, $start, $length, $charset);
        } else {
            $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
            $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
            $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
            $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
            preg_match_all($re[$charset], $str, $match);
            $content = join('', array_slice($match[0], $start, $length));
        }
        if ($str != $content) {
            $content .= $suffix;
        }

        return $content;
    }
}
